#include "types.h"
#include "semaphore.h"
#include "user.h"

struct semaphore* semaphore_create(int initial_semaphore_value){
	
	if(initial_semaphore_value < 0){
		return 0;
	}
	
	struct semaphore* counting_semaphore = malloc(sizeof(struct semaphore));

	counting_semaphore->binary_sem_id_S1 = binary_sem_create();
	counting_semaphore->binary_sem_id_S2 = binary_sem_create();
	
	if(counting_semaphore->binary_sem_id_S1 == -1 || counting_semaphore->binary_sem_id_S2 == -1){
		return 0;//no semaphore available	
	}
	
	//this is an end case where the only way to enter a critical section is with executing sem up first
	//so we execute sem down on S2
	if(initial_semaphore_value == 0){
		binary_sem_down(counting_semaphore->binary_sem_id_S2);
	}

	counting_semaphore->value = initial_semaphore_value;

	return counting_semaphore;
}

void sem_up(struct semaphore* sem ){
	binary_sem_down(sem->binary_sem_id_S1);
	sem->value++;
	
	if(sem->value == 1)
		binary_sem_up(sem->binary_sem_id_S2);

	binary_sem_up(sem->binary_sem_id_S1);
}

void sem_down(struct semaphore* sem ){
	binary_sem_down(sem->binary_sem_id_S2);
	binary_sem_down(sem->binary_sem_id_S1);
	sem->value--;

	if(sem->value > 0)
		binary_sem_up(sem->binary_sem_id_S2);

	binary_sem_up(sem->binary_sem_id_S1);
}

void destroy_sem(struct semaphore* sem ){
	free(sem);
}